﻿using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.MSBuild;
using SharpAnalyzer.Calculators;
using SharpAnalyzer.Entities;
using SharpAnalyzer.Utilities;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SharpAnalyzer
{
    public partial class FormMain : Form
    {
        public FormMain()
        {
            InitializeComponent();

            //button1_Click(this, EventArgs.Empty);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //SyntaxTree tree = CSharpSyntaxTree.ParseText(
            //    File.ReadAllText(@"C:\Projects\SharpAnalyzer\Form1.cs"));
            //var root = tree.GetRoot();

            //var parameters = 
            //    from method in root.DescendantNodes().OfType<MethodDeclarationSyntax>()
            //    where method.Identifier.ValueText == "button1_Click"
            //    select method.ParameterList.Parameters.ToArray();
        }

        private void btnAnalyze_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() != DialogResult.OK)
                return;

            //string inputfile = @"D:\Projects\Cerenade.eCMS.root\Cerenade.eCMS\Cerenade.eCMS.sln";
            //string inputfile = @"D:\Projects\SharpAnalyzer\SharpAnalyzer.sln";
            string inputfile = openFileDialog1.FileName;

            btnAnalyze.Enabled = false;
            lblLog.Text = "";
            backgroundWorker1.RunWorkerAsync(inputfile);
        }

        private void Log(string log)
        {
            lblLog.Text = log;
        }

        CodeMetricsReport report = null;
        DateTime startDT;
        private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            string inputFile = (string)e.Argument;
            string outputFile = "_output.xml"; // TODO: Ask for destination file using SaveFileDialog
            report = null;

            backgroundWorker1.ReportProgress(-1, "start analyzing " + Path.GetFileName(inputFile) + " ...");
            startDT = DateTime.Now;
            bool ignoreGeneratedCode = true;
            FileInfo fileInfo = new FileInfo(inputFile);
            if (fileInfo.Exists)
            {
                switch (fileInfo.Extension.ToLower())
                {
                    case ".sln":
                        report = SolutionMetricsCalculator.CalculateFromSolution(inputFile, ignoreGeneratedCode);
                        break;
                    case ".csproj":
                        report = SolutionMetricsCalculator.CalculateFromProject(inputFile, ignoreGeneratedCode);
                        break;
                    default:
                        backgroundWorker1.ReportProgress(-2, "Bad file type");
                        return;
                }
                report.WriteTo(outputFile);

                backgroundWorker1.ReportProgress(-1, "Done in " + (DateTime.Now - startDT).ToString());
            }
            else
                backgroundWorker1.ReportProgress(-2, "File not found!");
        }

        private void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
        {
            if (e.ProgressPercentage == -1)
                Log((string)e.UserState);
            else if (e.ProgressPercentage == -2)
                Log("Error: " + (string)e.UserState);
        }

        Stack<object> clickedItems = new Stack<object>();
        object clickedItem = null;
        private void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
        {
            btnAnalyze.Enabled = true;
            if (report != null)
            {
                reportGrid.Rows.Clear();
                reportGrid.Columns.Clear();

                reportGrid.Columns.Add(new DataGridViewColumn() { Name = "entity", HeaderText = "Entity", Width = 400, AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill, CellTemplate = new DataGridViewLinkCell() });
                reportGrid.Columns.Add(new DataGridViewColumn() { Name = "entityObject", Visible = false, CellTemplate = new DataGridViewTextBoxCell() });
                reportGrid.Columns.Add(new DataGridViewColumn() { Name = "name", HeaderText = "Name", Width = 150, CellTemplate = new DataGridViewTextBoxCell() });
                reportGrid.Columns.Add(new DataGridViewColumn() { Name = "value", HeaderText = "Value", Width = 50, CellTemplate = new DataGridViewTextBoxCell() });

                ShowReportInGrid();

                reportGrid.Enabled = true;
            }
        }

        private void ShowReportInGrid()
        {
            reportGrid.Rows.Clear();
            clickedItems.Clear();
            clickedItem = null;

            reportGrid.Rows.Add(Path.GetFileName(report.InputFile) + " (Solution/Project)", report);
            foreach (var metric in report.Metrics)
                reportGrid.Rows.Add(null, null, metric.Name, metric.ValueText);
        }

        private void reportGrid_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {

            if (e.ColumnIndex == 0 && e.RowIndex >= 0 &&
                reportGrid.Rows[e.RowIndex].Cells[e.ColumnIndex].Value != null)
            {
                if (reportGrid.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString() == "<BACK>")
                    clickedItem = clickedItems.Pop();
                else
                {
                    clickedItems.Push(clickedItem);
                    clickedItem = reportGrid.Rows[e.RowIndex].Cells[1].Value;
                }

                if (clickedItem == null)
                {
                    ShowReportInGrid();
                }
                else if (clickedItem is CodeMetricsReport)
                {
                    reportGrid.Rows.Clear();
                    reportGrid.Rows.Add("<BACK>");

                    foreach (var module in report.Projects)
                    {
                        reportGrid.Rows.Add(module.Name + " (Module/Assembly)", module);
                        foreach (var metric in module.Metrics)
                            reportGrid.Rows.Add(null, null, metric.Name, metric.ValueText);
                    }
                }
                else if (clickedItem is Entities.Project)
                {
                    reportGrid.Rows.Clear();
                    reportGrid.Rows.Add("<BACK>");

                    foreach (var namespaceT in (clickedItem as Entities.Project).Namespaces)
                    {
                        reportGrid.Rows.Add(namespaceT.Name + " (Namespace)", namespaceT);
                        foreach (var metric in namespaceT.Metrics)
                            reportGrid.Rows.Add(null, null, metric.Name, metric.ValueText);
                    }
                }
                else if (clickedItem is Namespace)
                {
                    reportGrid.Rows.Clear();
                    reportGrid.Rows.Add("<BACK>");

                    foreach (var type in (clickedItem as Namespace).Types)
                    {
                        reportGrid.Rows.Add(type.Name + " (" + type.Kind.ToString() + ")", type);
                        foreach (var metric in type.Metrics)
                            reportGrid.Rows.Add(null, null, metric.Name, metric.ValueText);
                    }
                }
                else if (clickedItem is Entities.Type)
                {
                    reportGrid.Rows.Clear();
                    reportGrid.Rows.Add("<BACK>");

                    foreach (var member in (clickedItem as Entities.Type).Members)
                    {
                        reportGrid.Rows.Add(member.DisplayName + " (" + member.Kind.ToString() + ")", member);
                        foreach (var metric in member.Metrics)
                            reportGrid.Rows.Add(null, null, metric.Name, metric.ValueText);
                    }
                }
                else if (clickedItem is Entities.Member)
                {
                    // TODO: nothing to do at this point!
                    clickedItems.Pop();
                }
            }
        }
    }
}

